//
// GPSMapEdit
// (c) Konstantin Galichsky (kg@geopainting.com), 2002-2007
//
// Split objects to elements distributed over levels.
//

# include "StdAfx.h"
# include "Resource.h"
# include "SplitRgnLevels.h"
# include "UndoRedo.h"
# include "Map.h"
# include "MapView.h"
# include "Load.h"
# include "Status.h"
# include "fast_floor.h"
# include "Globals.h"

class CSplitRgnLevelsAction : public CEditAction {
  public:
	virtual void GetName (string_t & _str) const {_str.append ("split objects by levels");}
	virtual cu_t CanUndo () const {return cuBackup;}
	virtual bool Do ();
	virtual void Undo () {}
	virtual void Redo () {}
};

bool CSplitRgnLevelsAction::Do () {
	CCritSec::CLock lock (g_cs);

	if (g_map.Levels.size () < 2)
		// Nothing to do!
		return true;

	const size_t cTotalRgns = g_map.GetRgnCount ();
	size_t cRgnsProcessed = 0;

	SetStatus (GetStr (IDS_STATUS_SPLITTING));
	SetProgressStatus (0);

	for (size_t cKind = 0; cKind < rkMax; ++ cKind) {
		layer_t & layer = g_map.layers [cKind];
		rgns_t & rgns = layer.rgns;

		for (rgns_t::iterator iRgn = rgns.begin (); iRgn != rgns.end (); ++ iRgn) {
			rgn_t & rgn = * iRgn;
			if (rgn.IsDeleted () || rgn.IsWTR ())
				continue;

			typedef std::map<size_t, rgn_t *> lev2rgns_t;
			lev2rgns_t lev2rgns;

			const size_t cElements = rgn.elements.size ();
			if (cElements != 0) {
				rgn_element_t & element0 = rgn.elements [0];

				for (size_t cElement = 1; cElement < cElements; ++ cElement) {
					rgn_element_t & element = rgn.elements [cElement];
					if (element.bDeleted)
						continue;

					if (element.cLevel == element0.cLevel)
						continue;

					rgn_t * pRgn;
					lev2rgns_t::iterator i = lev2rgns.find (element.cLevel);
					if (i != lev2rgns.end ()) {
						pRgn = i->second;
					} else {
						pRgn = & g_map.CreateRgn ((RGN_KIND) cKind);

						// Initialize the object.
						pRgn->dwFlags    = rgn.dwFlags;

						pRgn->strLabel   = rgn.strLabel;
						pRgn->strComment = rgn.strComment;
						if (rgn.pExtra)
							pRgn->pExtra = rgn.pExtra;

						pRgn->SetType (rgn.pTypeDesc, rgn.GetType (), rgn.Kind);

						lev2rgns [element.cLevel] = pRgn;
					}

					// Copy element to the new rgn.
					pRgn->elements.push_back (rgn_element_t ());
					pRgn->elements.back ().swap (element);
					element.bDeleted = true;

					pRgn->dwFlags |= rgn_t::fModified;
				}
			}

			const size_t cOrigins = rgn.origins.size ();
			if (cOrigins != 0) {
				rgn_origin_t & origin0 = rgn.origins [0];

				for (size_t cOrigin = 1; cOrigin < cOrigins; ++ cOrigin) {
					rgn_origin_t & origin = rgn.origins [cOrigin];
					if (origin.bDeleted)
						continue;

					if (origin.cLevel == origin0.cLevel)
						continue;

					rgn_t * pRgn;
					lev2rgns_t::iterator i = lev2rgns.find (origin.cLevel);
					if (i != lev2rgns.end ()) {
						pRgn = i->second;
					} else {
						pRgn = & g_map.CreateRgn ((RGN_KIND) cKind);

						// Initialize the object.
						pRgn->dwFlags     = rgn.dwFlags;

						pRgn->strLabel    = rgn.strLabel;
						pRgn->strComment  = rgn.strComment;
//						pRgn->uchEndLevel = rgn.uchEndLevel;
						if (rgn.pExtra)
							pRgn->pExtra  = rgn.pExtra;

						pRgn->SetType (rgn.pTypeDesc, rgn.GetType (), rgn.Kind);

						lev2rgns [origin.cLevel] = pRgn;
					}

					// Copy origin to the new rgn.
					pRgn->origins.push_back (origin);
					origin.bDeleted = true;

					pRgn->dwFlags |= rgn_t::fModified;
				}
			}

			if (! lev2rgns.empty ()) {
				for (lev2rgns_t::iterator i = lev2rgns.begin (); i != lev2rgns.end (); ++ i)
					i->second->RefreshAttributes (g_map, false);

				rgn.RefreshAttributes (g_map, false);
			}

			++ cRgnsProcessed;
			SetProgressStatus (cRgnsProcessed*100/cTotalRgns);
		}
	}

	g_map.RefreshDrawOrder ();

	SetStatusReady ();

	return true;
}

///////////////////////////

void SplitRgnLevels () {
	PerformEditAction (new CSplitRgnLevelsAction ());
	Refresh ();
}
